// Learn TypeScript:
//  - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

import FileModule from "./FileModule";
import HttpModule from "./HttpModule";
import LogModule from "./LogModule";
import { septdata } from "../proto/septdata.js";
import DataUtil from "../util/DataUtil";
import {ApiFilePath, ApiType, SWPlateType} from "../define/ApiDefine";
import TimeModule from "./TimeModule";
import TushareModule from "./TushareModule";
const {ccclass, property} = cc._decorator;

@ccclass
export default class SWPlateModule {
    public static _instance: SWPlateModule = null;

    private _plate1: septdata.SwClassifyItem[] = null;

    private _plate2: septdata.SwClassifyItem[] = null;

    private _plate3: septdata.SwClassifyItem[] = null;

    private _members: septdata.SwMemberItem[] = null;

    private _memberMap: { [key: string]: septdata.SwMemberItem } = {};

    private _dailyMap: { [key: string]: septdata.SwDailyMap } = {};

    private _plateMemberMap: { [key: string]: septdata.SwMemberItem[] } = {};

    private recentDate: string = "";
    static getInstance(): SWPlateModule {
        if (SWPlateModule._instance == null) {
            SWPlateModule._instance = new SWPlateModule();
        }
        return SWPlateModule._instance;
    }

    async initModule () {
        FileModule.checkOrMakeDir(ApiFilePath.SWDataPath);
        FileModule.checkOrMakeDir(ApiFilePath.SWDailyPath);
        if (FileModule.isFileExist(ApiFilePath.SWPlateData) == false) {
            await this.initHttpData();
        } else {
            let buffer = FileModule.loadUint8Array(ApiFilePath.SWPlateData);
            let swClassifyData = septdata.SwClassifyData.decode(buffer);
            this._plate1 = DataUtil.convertToArray<septdata.SwClassifyItem>(swClassifyData.plate1);
            this._plate2 = DataUtil.convertToArray<septdata.SwClassifyItem>(swClassifyData.plate2);
            this._plate3 = DataUtil.convertToArray<septdata.SwClassifyItem>(swClassifyData.plate3);
            this._members = DataUtil.convertToArray<septdata.SwMemberItem>(swClassifyData.members);
        } 
        LogModule.log('正在加载行业数据');
        this.decodeMembersData();
        LogModule.log('正在加载当日行业行情');
        await this.initPlateDaily();
    }

    ///////////////行业数据////////////////////////////////
    // index_code	str	Y	指数代码
    // industry_name	str	Y	行业名称
    // parent_code	str	Y	父级代码
    // level	str	Y	行业名称
    // industry_code	str	Y	行业代码
    // is_pub	str	Y	是否发布了指数
    // src	str	N	行业分类（SW申万）

    ///////////////成分数据////////////////////////////////
    //l1_code	str	Y	一级行业代码
    //l1_name	str	Y	一级行业名称
    //l2_code	str	Y	二级行业代码
    //l2_name	str	Y	二级行业名称
    //l3_code	str	Y	三级行业代码
    //l3_name	str	Y	三级行业名称
    //ts_code	str	Y	成分股票代码
    //name	str	Y	成分股票名称
    //in_date	str	Y	纳入日期
    //out_date	str	Y	剔除日期
    //is_new	str	Y	是否最新Y是N否

    async initHttpData () { 
        let plateArray = await HttpModule.postAsync({
            api_name: ApiType.SWClassify,
            params: null,
            fields: 'index_code,industry_name,parent_code,level,industry_code,is_pub',
        });

        let plateData = DataUtil.convertToArray<septdata.SwClassifyItem>(plateArray);
        await this.decodePlateData(plateData);
        let SwClassifyData = septdata.SwClassifyData;
        let swClassifyData = new SwClassifyData();
        swClassifyData.plate1 = this._plate1;
        swClassifyData.plate2 = this._plate2;
        swClassifyData.plate3 = this._plate3;
        swClassifyData.members = this._members;
        let buffer = septdata.SwClassifyData.encode(swClassifyData).finish();
        FileModule.saveUint8Array(ApiFilePath.SWPlateData, buffer);
    }

    async decodePlateData (plateData: septdata.SwClassifyItem[] = null) { 
        this._plate1 = [];
        this._plate2 = [];
        this._plate3 = [];
        this._members = [];
        for (let index = 0; index < plateData.length; index++) {
            let item = plateData[index] as septdata.SwClassifyItem;
            // if (item.is_pub != "Y") continue;
            if (item.level == "L1") {
                this._plate1.push(item);
            } else if (item.level == "L2") {
                this._plate2.push(item);
            } else if (item.level == "L3") {
                this._plate3.push(item);
            }
        }

        for (let index = 0; index < this._plate1.length; index++) {
            const element = this._plate1[index];
            let params = {
                l1_code: element.index_code,
            };
            let memberArray = await HttpModule.postAsync({
                api_name: ApiType.SWMemberAll,
                params: params,
                fields: 'l1_code,l1_name,l2_code,l2_name,l3_code,l3_name,ts_code,name,is_new',
            });
            let members = DataUtil.convertToArray<septdata.SwMemberItem>(memberArray);
            this._members = this._members.concat(members);
        }
    }

    decodeMembersData() {
        this._memberMap = {};
        this._plateMemberMap = {};
        for (let index = 0; index < this._members.length; index++) {
            let item = this._members[index] as septdata.SwMemberItem;
            this._memberMap[item.ts_code] = item;
            if (item.l1_code != "" && item.l1_code != null) {
                this._plateMemberMap[item.l1_code] = this._plateMemberMap[item.l1_code] || [];
                this._plateMemberMap[item.l1_code].push(item);
            }
            if (item.l2_code != "" && item.l2_code != null) {
                this._plateMemberMap[item.l2_code] = this._plateMemberMap[item.l2_code] || [];
                this._plateMemberMap[item.l2_code].push(item);
            }
            if (item.l3_code != "" && item.l3_code != null) {
                this._plateMemberMap[item.l3_code] = this._plateMemberMap[item.l3_code] || [];
                this._plateMemberMap[item.l3_code].push(item);
            }
        }
    }

    // ts_code	str	Y	指数代码
    // trade_date	str	Y	交易日期
    // name	str	Y	指数名称
    // open	float	Y	开盘点位
    // low	float	Y	最低点位
    // high	float	Y	最高点位
    // close	float	Y	收盘点位
    // change	float	Y	涨跌点位
    // pct_change	float	Y	涨跌幅
    // vol	float	Y	成交量（万股）
    // amount	float	Y	成交额（万元）
    // pe	float	Y	市盈率
    // pb	float	Y	市净率
    // float_mv	float	Y	流通市值（万元）
    // total_mv	float	Y	总市值（万元）
    
    async initPlateDaily() {
        let dates = TimeModule.getInstance().getRecentTradeDates(5);
        for (let index = 0; index < dates.length; index++) {
            const date: string = dates[index];
            let file = ApiFilePath.SWDailyData + date + ".data";
            let swDailyData: septdata.SwDailyData = null;
            if (FileModule.isFileExist(file)) {
                let buffer = FileModule.loadUint8Array(file);
                swDailyData = septdata.SwDailyData.decode(buffer);
            } else {
                let params = { trade_date: date};
                let dailys = await HttpModule.postAsync({
                    api_name: ApiType.SWDaily,
                    params: params,
                    fields: 'ts_code,trade_date,name,open,low,high,close,change,pct_change,vol,amount,pe,pb,float_mv,total_mv',
                });
                if (dailys == null || dailys.length == 0) continue;
                let datas = DataUtil.convertToArray<septdata.SwDailyItem>(dailys);
                swDailyData = new septdata.SwDailyData();
                swDailyData.datas = datas;
                let buffer = septdata.SwDailyData.encode(swDailyData).finish();
                FileModule.saveUint8Array(file, buffer);
            }
            this._dailyMap[date] = this.decodeSwDailyMap(swDailyData);

            if (this.recentDate == "") {
                this.recentDate = date;
            }
        }
    }

    decodeSwDailyMap(dailyData: septdata.SwDailyData): septdata.SwDailyMap {
        let swDailyMap = new septdata.SwDailyMap();
        for (let index = 0; index < dailyData.datas.length; index++) {
            const item = dailyData.datas[index];
            swDailyMap[item.ts_code] = item;
        }
        return swDailyMap;
    }

    getPlateData (type) {
        let plate = null;
        switch (type) {
            case SWPlateType.Industry:
                plate = this._plate1;
                break;
            case SWPlateType.Subtrade:
                plate = this._plate2;
                break;
            case SWPlateType.Mintrade:
                plate = this._plate3;
                break;
            default:
                break;
        }
        let ret = [];
        let datas = this._dailyMap[this.recentDate];
        for (let i = 0; i < plate.length; i++) {
            const item = plate[i];
            const data = datas[item.index_code];
            if (data != null) {
                let obj = DataUtil.shallowCopy(data);
                obj["stockCount"] = this._plateMemberMap[item.index_code].length;
                ret.push(obj);
            }
        }
        return ret;
    }

    getPlateMembers (indexCode) {
        let members = this._plateMemberMap[indexCode];
        let ret = [];
        for (let i = 0; i < members.length; i++) {
            const item = members[i];
            let itemData = TushareModule.getInstance().getStockRecentInfo(item.ts_code);
            if (itemData != null) {
                ret.push(itemData);
            }
        }

        ret.sort((a, b) => {
            return a.pb - b.pb;
        });
        return ret;
    }

    // update (dt) {}
}
